#!/usr/bin/python
# coding=utf-8
import win32api
import win32con
import sys
import os
import hashlib


# 变量名对齐函数
def def_align(str_def, max_len):
    name_len = len(str_def)
    if name_len > max_len:
        win32api.MessageBox(0, "名字过长，最大限制为%d字符" % max_len, "提醒", win32con.MB_OK)
        exit(0)
    space_num = max_len - name_len + 1  # 至少加一个空格
    if space_num > 0:  # 用空格补齐len个字符长度
        i = 0
        while i < space_num:
            str_def += " "
            i += 1
    return str_def

# 行处理函数
def line_split(line):
    list1 = line.split('#')      # 分离注释
    list2 = list1[0].split('=')  # 分离默认值
    name = list2[0].replace('\n', '')  # 去掉换行符
    name = name.replace(' ', '')   # 去掉空格
    default = ""
    min = ""
    max = ""
    comment = ""
    if len(list2) > 1:  # 有默认值
        value = list2[1].replace(' ', '')
        default, min, max = value.split(',') # 分离默认值，最小值和最大值
    if len(list1) > 1:
        comment = "   //" + list1[1].replace('\n', '')
    return name, default.replace('\n', ''), min.replace('\n', ''), max.replace('\n', ''), comment


# 判断文件是否更改
def md5_modified_check(obj_path):
    md5_file_path = obj_path + "\\registers_md5.dat"
    fpr = open(obj_path + "\\registers.def", 'r', encoding='utf-8')
    new_md5 = hashlib.md5(fpr.read().encode('utf-8')).hexdigest()
    fpr.close()

    old_md5 = ""
    if os.path.exists(md5_file_path):  # md5文件存在，读取old_md5
        fmd5 = open(obj_path + "\\registers_md5.dat", 'r')
        old_md5 = fmd5.read()
        fmd5.close()

    # 比较md5值是否相等
    print("old_md5:" + old_md5)
    print("new_md5:" + new_md5)
    if not old_md5 == new_md5: # 不相等则被更改
        fmd5 = open(obj_path + "\\registers_md5.dat", 'w')
        fmd5.truncate() #清空
        fmd5.write(new_md5) #写入新的md5
        fmd5.close()
        return True
    else:
        return False



# 程序开始
obj_path = sys.argv[1]
if not md5_modified_check(obj_path):
    print("no change\n")
    exit(0)

# 打开register.h
fpwh = open(obj_path + "\\registers.h", 'w')
# 清空
fpwh.truncate()
# 写入注释头
fpwh.write("\
/*---------------------------------------------------------------------\n\
 * File name: registers.h\n\
 *\n\
 * Copyright (c) <2020-2022>, <ChenLong>\n\
 *\n\
 * All rights reserved.\n\
 *\n\
 * Author: ChenLong\n\
 * Email: worldlong@foxmail.com\n\
 *--------------------------------------------------------------------*/\n")
fpwh.write("#pragma once\n")
fpwh.write("#include <stdint.h>\n")
fpwh.write("/*\n\
All registers are 16 bits\n\
*/\n")

# 打开register.cpp
fpwc = open(obj_path + "\\registers.cpp", 'w')
# 清空
fpwc.truncate()
# 写入注释头
fpwc.write("\
/*---------------------------------------------------------------------\n\
 * File name: registers.cpp\n\
 *\n\
 * Copyright (c) <2020-2022>, <ChenLong>\n\
 *\n\
 * All rights reserved.\n\
 *\n\
 * Author: ChenLong\n\
 * Email: worldlong@foxmail.com\n\
 *--------------------------------------------------------------------*/\n")
fpwc.write("#include \"registers.h\"\n")
fpwc.write("/*\n*/\n")
fpwc.write("__no_init uint16_t reg_table[REG_NUMBER];\n")
fpwc.write("/*\n*/\n")

# 打开RegistersX.cs
fpwcs = open(obj_path + "\\RegistersX.cs", 'w')
# 清空
fpwcs.truncate()
# 写入注释头
fpwcs.write("\
/*---------------------------------------------------------------------\n\
 * File name: RegistersX.cs\n\
 *\n\
 * Copyright (c) <2020-2022>, <ChenLong>\n\
 *\n\
 * All rights reserved.\n\
 *\n\
 * Author: ChenLong\n\
 * Email: worldlong@foxmail.com\n\
 *--------------------------------------------------------------------*/\n")
fpwcs.write("using System;\n")
fpwcs.write("\
/*\n\
All registers are 16 bits.\n\
*/\n")
fpwcs.write("namespace RegistersX\n{\n")
fpwcs.write("\tstatic class Registers\n\t{\n")

# 指定名字的最大长度
DEF_NAME_LENGTH_MAX = 40
reg_addr = 0
reg_type_name = "*"
bit_mask_name = "*"
bit_mask_index = 0
nvd_reg_start = -1
nvd_reg_end = -1
nvd_reg_table_cpp = "const uint16_t nvd_reg_table[][3]={\n"
nvd_reg_table_cs = ""

# 打开registers.def文件
fpr = open(obj_path + "\\registers.def", 'r', encoding='utf-8')
for line in fpr.readlines():
    if line.startswith("##"):  # 生成注释块
        # registers.h
        fpwh.write("/*********************************************\n")
        fpwh.write(" *" + line.replace("#", " "))
        fpwh.write(" *********************************************/\n")
        # RegistersX.cs
        fpwcs.write("\t\t/*********************************************\n")
        fpwcs.write("\t\t *" + line.replace("#", " "))
        fpwcs.write("\t\t *********************************************/\n")
    elif line.startswith("#"):  # 生成注释行
        fpwh.write(line.replace("#", "//"))
        fpwcs.write("\t\t" + line.replace("#", "//"))
    elif line.startswith("\n"):  # 直接换行
        fpwh.write(line)
        fpwcs.write(line)
    elif line.startswith("%NVD_REG_START"):
        nvd_reg_start = reg_addr
        fpwh.write("/*---------nvd registers start-----------*/\n")
        fpwcs.write("\t\t/*---------nvd registers start-----------*/\n")
        # NVD_REG_START定义
        str_def = "#define NVD_REG_START"
        str_def = def_align(str_def, DEF_NAME_LENGTH_MAX) + str(nvd_reg_start) + "\n"
        fpwh.write(str_def)
        fpwcs.write("\t\tpublic static ushort NVD_REG_START = " + str(nvd_reg_start) + ";\n")
    elif line.startswith("%NVD_REG_END"):
        # 寄存器组结束
        nvd_reg_end = reg_addr - 1
        str_def = "#define " + reg_type_name + "_REG_END"
        str_def = def_align(str_def, DEF_NAME_LENGTH_MAX) + str(nvd_reg_end) + comment + "\n"
        fpwh.write(str_def)
        fpwcs.write("\t\tpublic static ushort " + reg_type_name + "_REG_END = " + str(nvd_reg_end) + ";\n")
        # NVD_REG_END定义
        str_def = "#define NVD_REG_END"
        str_def = def_align(str_def, DEF_NAME_LENGTH_MAX) + str(nvd_reg_end) + "\n"
        fpwh.write(str_def)
        fpwh.write("/*---------nvd registers end-----------*/\n")
        fpwcs.write("\t\tpublic static ushort NVD_REG_END = " + str(nvd_reg_end) + ";\n")
        fpwcs.write("\t\t/*---------nvd registers end-----------*/\n")
        reg_type_name = "*"
    elif line[0].isalpha(): # 必须以字母开头
        name, default, min, max, comment = line_split(line)
        if name.startswith("REG"):  # 寄存器地址定义，为了保持格式统一，请连续定义寄存器地址
            name_list = name.split("_")
            new_type_name = name_list[1]
            if not new_type_name.startswith(reg_type_name):  # 新的寄存器组
                if not reg_type_name.startswith("*"):
                    str_def = "#define " + reg_type_name + "_REG_END"
                    str_def = def_align(str_def, DEF_NAME_LENGTH_MAX) + str(reg_addr - 1) + "\n"
                    fpwh.write(str_def)
                    fpwcs.write("\t\tpublic static ushort " + reg_type_name + "_REG_END = " + str(reg_addr - 1) + ";\n")
                fpwh.write("/* " + new_type_name.lower() + " registers group */\n")
                fpwcs.write("\t\t/* " + new_type_name.lower() + " registers group */\n")
                if len(new_type_name) > 0:
                    str_def = "#define " + new_type_name + "_REG_START"
                    str_def = def_align(str_def, DEF_NAME_LENGTH_MAX) + str(reg_addr) + "\n"
                    fpwh.write(str_def)
                    fpwcs.write("\t\tpublic static ushort " + new_type_name + "_REG_START = " + str(reg_addr) + ";\n")
                reg_type_name = new_type_name
            str_def = "#define " + name
            str_def = def_align(str_def, DEF_NAME_LENGTH_MAX) + str(reg_addr) + comment + "\n"
            fpwh.write(str_def)
            fpwcs.write("\t\tpublic static ushort " + name + " = " + str(reg_addr) + ";" + comment + "\n")
            # nvd_reg_table
            if nvd_reg_start >= 0 and nvd_reg_end < 0:
                # 默认值
                if len(default) > 0:
                    nvd_reg_table_cpp += "{(uint16_t)" + default
                    nvd_reg_table_cs += "\t\t\t{(ushort)" + default
                else:
                    nvd_reg_table_cpp += "{(uint16_t)0"
                    nvd_reg_table_cs += "\t\t\t{(ushort)0"
                # 最小值
                if len(min) > 0:
                    nvd_reg_table_cpp += ", (uint16_t)" + min
                    nvd_reg_table_cs += ", (ushort)" + min
                else:
                    nvd_reg_table_cpp += ", (uint16_t)0"
                    nvd_reg_table_cs += ", (ushort)0"
                # 最大值
                if len(max) > 0:
                    nvd_reg_table_cpp += ", (uint16_t)" + max + "},\n"
                    nvd_reg_table_cs += ", (ushort)" + max + "},\n"
                else:
                    nvd_reg_table_cpp += ", (uint16_t)0},\n"
                    nvd_reg_table_cs += ", (ushort)0},\n"
            reg_addr += 1
        else: # bit mask define
            if not name.startswith(bit_mask_name):  # 新的bit mask组
                name_list = name.split("_")
                bit_mask_name = name_list[0]
                bit_mask_index = 0
            str_def = "#define " + name
            str_def = def_align(str_def, DEF_NAME_LENGTH_MAX) + "(uint32_t)(1 << " + str(bit_mask_index) + ")" + comment + "\n"
            fpwh.write(str_def)
            fpwcs.write("\t\tpublic static uint " + name + " = (uint)1 << " + str(bit_mask_index) + ";" + comment + "\n")
            bit_mask_index += 1
str_def = "#define " + reg_type_name + "_REG_END"
str_def = def_align(str_def, DEF_NAME_LENGTH_MAX) + str(reg_addr - 1) + "\n"
fpwh.write(str_def)
fpwcs.write("\t\tpublic static ushort " + reg_type_name + "_REG_END = " + str(reg_addr - 1) + ";\n")

# registers.h
fpwh.write("/*\n*/\n")
fpwh.write("#define REG_NUMBER                       %d\n" % reg_addr)
fpwh.write("#define NVD_REG_NUMBER                   %d\n" % (nvd_reg_end - nvd_reg_start + 1))
fpwh.write("/*\n*/\n")
fpwh.write("extern uint16_t reg_table[REG_NUMBER];\n")
fpwh.write("extern const uint16_t nvd_reg_table[][3];\n")
fpwh.write("void nvd_reg_reset();\n")
fpwh.write("uint16_t nvd_reg_limit(int addr, uint16_t data);\n")
fpwh.write("int16_t nvd_reg_limit(int addr, int16_t data);\n")
fpwh.write("void reg16_write(int addr, uint16_t data);\n")
fpwh.write("void reg32_write(int addr, uint32_t data);\n")
fpwh.write("void reg48_write(int addr, uint64_t data);\n")
fpwh.write("void reg64_write(int addr, uint64_t data);\n")
fpwh.write("uint16_t reg16_read(int addr);\n")
fpwh.write("uint32_t reg32_read(int addr);\n")
fpwh.write("uint64_t reg48_read(int addr);\n")
fpwh.write("uint64_t reg64_read(int addr);\n")

# registers.cpp
fpwc.write(nvd_reg_table_cpp + "};\n")
fpwc.write("/*\n*/\n")
fpwc.write("\
void nvd_reg_reset()\n\
{\n\
    for(int i = NVD_REG_START; i <= NVD_REG_END; i++) {\n\
        reg_table[i] = nvd_reg_table[i - NVD_REG_START][0];\n\
    }\n\
}\n")
fpwc.write("/*\n*/\n")
fpwc.write("\
uint16_t nvd_reg_limit(int addr, uint16_t data)\n\
{\n\
    int index = addr - NVD_REG_START;\n\
    if(data < nvd_reg_table[index][1]) {\n\
        data = nvd_reg_table[index][1];\n\
    } else if(data > nvd_reg_table[index][2]) {\n\
        data = nvd_reg_table[index][2];\n\
    }\n\
    return data;\n\
}\n")

fpwc.write("/*\n*/\n")
fpwc.write("\
int16_t nvd_reg_limit(int addr, int16_t data)\n\
{\n\
    int index = addr - NVD_REG_START;\n\
    if(data < (int16_t)nvd_reg_table[index][1]) {\n\
        data = (int16_t)nvd_reg_table[index][1];\n\
    } else if(data > (int16_t)nvd_reg_table[index][2]) {\n\
        data = (int16_t)nvd_reg_table[index][2];\n\
    }\n\
    return data;\n\
}\n")

fpwc.write("/*\n*/\n")
fpwc.write("\
void reg16_write(int addr, uint16_t data)\n\
{\n\
    reg_table[addr] = data;\n\
}\n")

fpwc.write("/*\n*/\n")
fpwc.write("\
void reg32_write(int addr, uint32_t data)\n\
{\n\
    reg_table[addr] = data;\n\
    reg_table[addr + 1] = data >> 16;\n\
}\n")

fpwc.write("/*\n*/\n")
fpwc.write("\
void reg48_write(int addr, uint64_t data)\n\
{\n\
    reg_table[addr] = data;\n\
    reg_table[addr + 1] = data >> 16;\n\
    reg_table[addr + 2] = data >> 32;\n\
}\n")

fpwc.write("/*\n*/\n")
fpwc.write("\
void reg64_write(int addr, uint64_t data)\n\
{\n\
    reg_table[addr] = data;\n\
    reg_table[addr + 1] = data >> 16;\n\
    reg_table[addr + 2] = data >> 32;\n\
    reg_table[addr + 3] = data >> 48;\n\
}\n")

fpwc.write("/*\n*/\n")
fpwc.write("\
uint16_t reg16_read(int addr)\n\
{\n\
    return reg_table[addr];\n\
}\n")

fpwc.write("/*\n*/\n")
fpwc.write("\
uint32_t reg32_read(int addr)\n\
{\n\
    return ((uint32_t)reg_table[addr + 1] << 16) + (uint32_t)reg_table[addr];\n\
}\n")

fpwc.write("/*\n*/\n")
fpwc.write("\
uint64_t reg48_read(int addr)\n\
{\n\
    return ((uint64_t)reg_table[addr + 2] << 32) +\n\
           ((uint64_t)reg_table[addr + 1] << 16) +\n\
            (uint64_t)reg_table[addr];\n\
}\n")

fpwc.write("/*\n*/\n")
fpwc.write("\
uint64_t reg64_read(int addr)\n\
{\n\
    return ((uint64_t)reg_table[addr + 3] << 48) +\n\
           ((uint64_t)reg_table[addr + 2] << 32) +\n\
           ((uint64_t)reg_table[addr + 1] << 16) +\n\
            (uint64_t)reg_table[addr];\n\
}\n")

# registers.cs
fpwcs.write("\t\t/*\n\t\t*/\n")
fpwcs.write("\t\tpublic static ushort REG_NUMBER = %d;\n" % reg_addr)
nvd_number = nvd_reg_end - nvd_reg_start + 1
fpwcs.write("\t\tpublic static ushort NVD_REG_NUMBER = %d;\n" % nvd_number)
fpwcs.write("\t\tpublic static ushort[] regTable = new ushort[%d];\n" %reg_addr)
# fpwcs.write("\t\tpublic static ushort[ , ] nvdRegTable = new ushort[%d, 3]{\n" % nvd_number + nvd_reg_table_cs + "\t\t};\n")
#
# fpwcs.write("\t\t/*\n\t\t*/\n")
# fpwcs.write("\
# \t\tpublic static void NvdRegReset()\n\
# \t\t{\n\
# \t\t\tfor(int i = NVD_REG_START; i <= NVD_REG_END; i++) {\n\
# \t\t\t\tregTable[i] = nvdRegTable[i - NVD_REG_START, 0];\n\
# \t\t\t}\n\
# \t\t}\n")
#
# fpwcs.write("\t\t/*\n\t\t*/\n")
# fpwcs.write("\
# \t\tpublic static ushort NvdRegLimit(int addr, ushort data)\n\
# \t\t{\n\
# \t\t\tint index = addr - NVD_REG_START;\n\
# \t\t\tif(data < nvdRegTable[index, 1]) {\n\
# \t\t\t\tdata = nvdRegTable[index, 1];\n\
# \t\t\t} else if(data > nvdRegTable[index, 2]) {\n\
# \t\t\t\tdata = nvdRegTable[index, 2];\n\
# \t\t\t}\n\
# \t\t\treturn data;\n\
# \t\t}\n")
#
# fpwcs.write("\t\t/*\n\t\t*/\n")
# fpwcs.write("\
# \t\tpublic static short NvdRegLimit(int addr, short data)\n\
# \t\t{\n\
# \t\t\tint index = addr - NVD_REG_START;\n\
# \t\t\tif(data < (short)nvdRegTable[index, 1]) {\n\
# \t\t\t\tdata = (short)nvdRegTable[index, 1];\n\
# \t\t\t} else if(data > (short)nvdRegTable[index, 2]) {\n\
# \t\t\t\tdata = (short)nvdRegTable[index, 2];\n\
# \t\t\t}\n\
# \t\t\treturn data;\n\
# \t\t}\n")

fpwcs.write("\t\t/*\n\t\t*/\n")
fpwcs.write("\
\t\tpublic static void SetAll(ushort val)\n\
\t\t{\n\
\t\t\tfor(int i = 0; i < REG_NUMBER; i++)\n\
\t\t\t{\n\
\t\t\t\tregTable[i] = val;\n\
\t\t\t}\n\
\t\t}\n")

fpwcs.write("\t\t/*\n\t\t*/\n")
fpwcs.write("\
\t\tpublic static ushort Reg16Read(int addr)\n\
\t\t{\n\
\t\t\treturn regTable[addr];\n\
\t\t}\n")

fpwcs.write("\t\t/*\n\t\t*/\n")
fpwcs.write("\
\t\tpublic static UInt32 Reg32Read(int addr)\n\
\t\t{\n\
\t\t\treturn ((uint)regTable[addr + 1] << 16) + (uint)regTable[addr];\n\
\t\t}\n")

fpwcs.write("\t\t/*\n\t\t*/\n")
fpwcs.write("\
\t\tpublic static UInt64 Reg48Read(int addr)\n\
\t\t{\n\
\t\t\treturn ((UInt64)regTable[addr + 2] << 32) +\n\
\t\t\t       ((UInt64)regTable[addr + 1] << 16) +\n\
\t\t\t        (UInt64)regTable[addr];\n\
\t\t}\n")

fpwcs.write("\t\t/*\n\t\t*/\n")
fpwcs.write("\
\t\tpublic static UInt64 Reg64Read(int addr)\n\
\t\t{\n\
\t\t\treturn ((UInt64)regTable[addr + 3] << 48) +\n\
\t\t\t       ((UInt64)regTable[addr + 2] << 32) +\n\
\t\t\t       ((UInt64)regTable[addr + 1] << 16) +\n\
\t\t\t        (UInt64)regTable[addr];\n\
\t\t}\n")

fpwcs.write("\t\t/*\n\t\t*/\n")
fpwcs.write("\
\t\tpublic static void Reg16Write(int addr, ushort data)\n\
\t\t{\n\
\t\t\tregTable[addr] = data;\n\
\t\t}\n")

fpwcs.write("\t\t/*\n\t\t*/\n")
fpwcs.write("\
\t\tpublic static void Reg32Write(int addr, UInt32 data)\n\
\t\t{\n\
\t\t\tregTable[addr] = (ushort)data;\n\
\t\t\tregTable[addr + 1] = (ushort)(data >> 16);\n\
\t\t}\n")

fpwcs.write("\t\t/*\n\t\t*/\n")
fpwcs.write("\
\t\tpublic static void Reg48Write(int addr, UInt64 data)\n\
\t\t{\n\
\t\t\tregTable[addr] = (ushort)data;\n\
\t\t\tregTable[addr + 1] = (ushort)(data >> 16);\n\
\t\t\tregTable[addr + 2] = (ushort)(data >> 32);\n\
\t\t}\n")

fpwcs.write("\t\t/*\n\t\t*/\n")
fpwcs.write("\
\t\tpublic static void Reg64Write(int addr, UInt64 data)\n\
\t\t{\n\
\t\t\tregTable[addr] = (ushort)data;\n\
\t\t\tregTable[addr + 1] = (ushort)(data >> 16);\n\
\t\t\tregTable[addr + 2] = (ushort)(data >> 32);\n\
\t\t\tregTable[addr + 3] = (ushort)(data >> 48);\n\
\t\t}\n")

fpwcs.write("\t}\n")
fpwcs.write("}\n")

fpr.close()
fpwh.close()
fpwc.close()
fpwcs.close()
exit(0)

